home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume22 / undel2 / part02 < prev    next >
Encoding:
Internet Message Format  |  1990-06-07  |  47.8 KB

  1. Subject:  v22i026:  MIT Athena delete/undelete programs, release 2, Part02/03
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: 2b340523 8b02d9f9 356246e7 e2c5c809
  5.  
  6. Submitted-by: "Jonathan I. Kamens" <jik@pit-manager.mit.edu>
  7. Posting-number: Volume 22, Issue 26
  8. Archive-name: undel2/part02
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 2 (of 3)."
  17. # Contents:  col.c expunge.c lsdel.c undelete.c util.c
  18. # Wrapped by rsalz@papaya.bbn.com on Mon May  7 16:54:00 1990
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'col.c' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'col.c'\"
  22. else
  23. echo shar: Extracting \"'col.c'\" \(5054 characters\)
  24. sed "s/^X//" >'col.c' <<'END_OF_FILE'
  25. X/*
  26. X * $Source: /afs/athena.mit.edu/user/j/jik/src/delete/RCS/col.c,v $
  27. X * $Author: jik $
  28. X *
  29. X * This program is part of a package including delete, undelete,
  30. X * lsdel, expunge and purge.  The software suite is meant as a
  31. X * replacement for rm which allows for file recovery.
  32. X * 
  33. X * Copyright (c) 1989 by the Massachusetts Institute of Technology.
  34. X * For copying and distribution information, see the file "mit-copyright.h."
  35. X */
  36. X
  37. X#if (!defined(lint) && !defined(SABER))
  38. X     static char rcsid_col_c[] = "$Header: /afs/athena.mit.edu/user/j/jik/src/delete/RCS/col.c,v 1.6 89/11/22 21:24:21 jik Exp $";
  39. X#endif
  40. X
  41. X/*
  42. X * Note that this function has a lot of options I'm not really using
  43. X * because I took it out of other code that needed a lot more
  44. X * versatility.
  45. X */
  46. X
  47. X#include <stdio.h>
  48. X#include <strings.h>
  49. X#include "errors.h"
  50. X#include "delete_errs.h"
  51. X#include "col.h"
  52. X#include "mit-copyright.h"
  53. X
  54. X
  55. Xstatic int calc_string_width(), calc_widths(), num_width();
  56. Xstatic void trim_strings();
  57. X
  58. Xint column_array(strings, num_to_print, screen_width, column_width,
  59. X         number_of_columns, margin, spread_flag, 
  60. X         number_flag, var_col_flag, outfile)
  61. Xchar **strings;
  62. XFILE *outfile;
  63. X{
  64. X     char buf[BUFSIZ];
  65. X     int updown, leftright, height;
  66. X     int string_width;
  67. X     int numwidth;
  68. X
  69. X     numwidth = num_width(num_to_print);
  70. X     if (! var_col_flag) {
  71. X      string_width = calc_string_width(column_width, margin, number_flag,
  72. X                       num_to_print);
  73. X      if (string_width <= 0) {
  74. X           set_error(COL_COLUMNS_TOO_THIN);
  75. X           error("calc_string_width");
  76. X           return error_code;
  77. X      }
  78. X      trim_strings(strings, num_to_print, string_width);
  79. X     } else if (calc_widths(strings, &screen_width, &column_width,
  80. X                &number_of_columns, num_to_print, &margin,
  81. X                spread_flag, number_flag)) {
  82. X      error("calc_widths");
  83. X      return error_code;
  84. X     }
  85. X     height = num_to_print / number_of_columns;
  86. X     if (num_to_print % number_of_columns)
  87. X      height++;
  88. X     
  89. X     if (number_flag) for (updown = 0; updown < height; updown++) {
  90. X      for (leftright = updown; leftright < num_to_print; ) {
  91. X           (void) sprintf(buf, "%*d. %s", numwidth, leftright+1,
  92. X                  strings[leftright]);
  93. X           if ((leftright += height) >= num_to_print)
  94. X            fprintf(outfile, "%s", buf );
  95. X           else
  96. X            fprintf(outfile, "%*s", -column_width, buf);
  97. X      }
  98. X      fprintf(outfile, "\n");
  99. X     } else for (updown = 0; updown < height; updown++) {
  100. X      for (leftright = updown; leftright < num_to_print; ) {
  101. X           (void) sprintf(buf, "%s", strings[leftright]);
  102. X           if ((leftright += height) >= num_to_print)
  103. X            fprintf(outfile, "%s", buf );
  104. X           else
  105. X            fprintf(outfile, "%*s", -column_width, buf);
  106. X      }
  107. X      fprintf(outfile, "\n");
  108. X     }
  109. X     return 0;
  110. X}
  111. X
  112. Xstatic int calc_string_width(column_width, margin, number_flag, max_number)
  113. X{
  114. X     int string_width;
  115. X     
  116. X     string_width = column_width - margin;
  117. X     if (number_flag)
  118. X      string_width = string_width - num_width(max_number) - strlen(". ");
  119. X     return string_width;
  120. X}
  121. X
  122. X
  123. Xstatic void trim_strings(strings, number, width)
  124. Xchar **strings;
  125. X{
  126. X     int loop;
  127. X     
  128. X     for (loop = 0; loop < number; loop++)
  129. X      if (strlen(strings[loop]) > width)
  130. X           strings[loop][width] = '\0';
  131. X}
  132. X
  133. X
  134. Xstatic int calc_widths(strings, screen_width, column_width, number_of_columns,
  135. X               num_to_print, margin, spread_flag, number_flag)
  136. Xint *screen_width, *column_width, *number_of_columns, *margin;
  137. Xchar **strings;
  138. X{
  139. X     int loop;
  140. X     int maxlen, templen;
  141. X     int spread;
  142. X     
  143. X     maxlen = templen = 0;
  144. X     for (loop = 0; loop < num_to_print; loop++)
  145. X      if (maxlen < (templen = strlen(strings[loop])))
  146. X           maxlen = templen;
  147. X
  148. X     *column_width = maxlen;
  149. X     
  150. X     if (number_flag)
  151. X      *column_width = *column_width + num_width(num_to_print) +
  152. X           strlen(". ");
  153. X
  154. X     if (! spread_flag) {
  155. X      *column_width += *margin;
  156. X      if (! *number_of_columns) {
  157. X           *number_of_columns = *screen_width / *column_width;
  158. X           if (! *number_of_columns) {
  159. X            (*number_of_columns)++;
  160. X            *column_width -= *margin;
  161. X            *margin = 0;
  162. X            *screen_width = *column_width;
  163. X           }
  164. X      }
  165. X      else
  166. X           *screen_width = *number_of_columns * *column_width;
  167. X     } else {
  168. X      if (! *number_of_columns) {
  169. X           *number_of_columns = *screen_width / (*column_width + *margin);
  170. X           if (! *number_of_columns) {
  171. X            (*number_of_columns)++;
  172. X            *screen_width = *column_width;
  173. X            *margin = 0;
  174. X           }
  175. X           spread = (*screen_width - *number_of_columns * *column_width)
  176. X            / *number_of_columns;
  177. X           *column_width += spread;
  178. X      }
  179. X      else {
  180. X           if (*number_of_columns * (*column_width + *margin) >
  181. X           *screen_width) {
  182. X            *column_width += *margin;
  183. X            *screen_width = *column_width;
  184. X           } else {
  185. X            spread = (*screen_width - (*number_of_columns *
  186. X                           *column_width)) /
  187. X                            *number_of_columns;
  188. X            *column_width += spread;
  189. X           }
  190. X      }
  191. X     }
  192. X     return 0;
  193. X}
  194. X
  195. X
  196. X           
  197. X
  198. Xstatic int num_width(number)
  199. Xint number;
  200. X{
  201. X     char buf[BUFSIZ];
  202. X
  203. X     (void) sprintf(buf, "%d", number);
  204. X     return strlen(buf);
  205. X}
  206. END_OF_FILE
  207. if test 5054 -ne `wc -c <'col.c'`; then
  208.     echo shar: \"'col.c'\" unpacked with wrong size!
  209. fi
  210. # end of 'col.c'
  211. fi
  212. if test -f 'expunge.c' -a "${1}" != "-c" ; then 
  213.   echo shar: Will not clobber existing file \"'expunge.c'\"
  214. else
  215. echo shar: Extracting \"'expunge.c'\" \(11211 characters\)
  216. sed "s/^X//" >'expunge.c' <<'END_OF_FILE'
  217. X/*
  218. X * $Source: /afs/athena.mit.edu/user/j/jik/src/delete/RCS/expunge.c,v $
  219. X * $Author: jik $
  220. X *
  221. X * This program is part of a package including delete, undelete,
  222. X * lsdel, expunge and purge.  The software suite is meant as a
  223. X * replacement for rm which allows for file recovery.
  224. X * 
  225. X * Copyright (c) 1989 by the Massachusetts Institute of Technology.
  226. X * For copying and distribution information, see the file "mit-copyright.h."
  227. X */
  228. X
  229. X#if (!defined(lint) && !defined(SABER))
  230. X     static char rcsid_expunge_c[] = "$Header: /afs/athena.mit.edu/user/j/jik/src/delete/RCS/expunge.c,v 1.13 89/12/28 14:45:15 jik Exp $";
  231. X#endif
  232. X
  233. X#include <stdio.h>
  234. X#include <sys/types.h>
  235. X#include <sys/time.h>
  236. X#include <sys/dir.h>
  237. X#include <sys/param.h>
  238. X#include <strings.h>
  239. X#include <sys/stat.h>
  240. X#include <com_err.h>
  241. X#include <errno.h>
  242. X#include "col.h"
  243. X#include "directories.h"
  244. X#include "util.h"
  245. X#include "pattern.h"
  246. X#include "expunge.h"
  247. X#include "shell_regexp.h"
  248. X#include "mit-copyright.h"
  249. X#include "delete_errs.h"
  250. X#include "errors.h"
  251. X
  252. Xextern char *realloc();
  253. Xextern time_t current_time;
  254. Xextern int errno;
  255. X
  256. Xchar *whoami;
  257. X
  258. Xtime_t timev;         /* minimum mod time before undeletion */
  259. X
  260. Xint  interactive,    /* query before each expunge */
  261. X     recursive,        /* expunge undeleted directories recursively */
  262. X     noop,        /* print what would be done instead of doing it */
  263. X     verbose,        /* print a line as each file is deleted */
  264. X     force,        /* do not ask for any confirmation */
  265. X     listfiles,        /* list files at toplevel */
  266. X     yield,        /* print yield of expunge at end */
  267. X     f_links,        /* follow symbolic links */
  268. X     f_mounts;        /* follow mount points */
  269. X
  270. Xint blocks_removed = 0;
  271. X
  272. X
  273. X
  274. X
  275. Xmain(argc, argv)
  276. Xint argc;
  277. Xchar *argv[];
  278. X{
  279. X     extern char *optarg;
  280. X     extern int optind;
  281. X     int arg;
  282. X
  283. X     initialize_del_error_table();
  284. X     
  285. X     whoami = lastpart(argv[0]);
  286. X     if (*whoami == 'p') { /* we're doing a purge */
  287. X      if (argc > 1) {
  288. X           set_error(PURGE_TOO_MANY_ARGS);
  289. X           error("");
  290. X           exit(1);
  291. X      }
  292. X      if (purge())
  293. X           error("purge");
  294. X      exit(error_occurred ? 1 : 0);
  295. X     }
  296. X     timev = 0;
  297. X     yield = interactive = recursive = noop = verbose = listfiles = force = 0;
  298. X     while ((arg = getopt(argc, argv, "t:irfnvlysm")) != EOF) {
  299. X      switch (arg) {
  300. X      case 't':
  301. X           timev = atoi(optarg);
  302. X           break;
  303. X      case 'i':
  304. X           interactive++;
  305. X           break;
  306. X      case 'r':
  307. X           recursive++;
  308. X           break;
  309. X      case 'f':
  310. X           force++;
  311. X           break;
  312. X      case 'n':
  313. X           noop++;
  314. X           break;
  315. X      case 'v':
  316. X           verbose++;
  317. X           break;
  318. X      case 'l':
  319. X           listfiles++;
  320. X           break;
  321. X      case 'y':
  322. X           yield++;
  323. X           break;
  324. X      case 's':
  325. X           f_links++;
  326. X           break;
  327. X      case 'm':
  328. X           f_mounts++;
  329. X           break;
  330. X      default:
  331. X           usage();
  332. X           exit(1);
  333. X      }
  334. X     }
  335. X     report_errors = ! force;
  336. X     
  337. X     if (optind == argc) {
  338. X      char *dir;
  339. X      dir = "."; /* current working directory */
  340. X      if (expunge(&dir, 1))
  341. X           error("expunging .");
  342. X     }
  343. X     else if (expunge(&argv[optind], argc - optind))
  344. X      error("expunge");
  345. X
  346. X     exit((error_occurred && (! force)) ? 1 : 0);
  347. X}
  348. X
  349. X
  350. X
  351. X
  352. X
  353. Xpurge()
  354. X{
  355. X     char *home;
  356. X     int retval;
  357. X     
  358. X     home = Malloc((unsigned) MAXPATHLEN);
  359. X     if (! home) {
  360. X      set_error(errno);
  361. X      error("purge");
  362. X      return error_code;
  363. X     }
  364. X     timev = interactive = noop = verbose = force = 0;
  365. X     yield = listfiles = recursive = 1;
  366. X     if (retval = get_home(home)) {
  367. X      error("purge");
  368. X      return retval;
  369. X     }
  370. X
  371. X     printf("Please be patient.... this may take a while.\n\n");
  372. X
  373. X     if (retval = expunge(&home, 1)) {
  374. X      error("expunge");
  375. X      return retval;
  376. X     }
  377. X     return 0;
  378. X}
  379. X
  380. X
  381. X
  382. X
  383. Xusage()
  384. X{
  385. X     fprintf(stderr, "Usage: %s [ options ] [ filename [ ... ]]\n", whoami);
  386. X     fprintf(stderr, "Options are:\n");
  387. X     fprintf(stderr, "     -r     recursive\n");
  388. X     fprintf(stderr, "     -i     interactive\n");
  389. X     fprintf(stderr, "     -f     force\n");
  390. X     fprintf(stderr, "     -t n   n-day-or-older expunge\n");
  391. X     fprintf(stderr, "     -n     noop\n");
  392. X     fprintf(stderr, "     -v     verbose\n");
  393. X     fprintf(stderr, "     -l     list files before expunging\n");
  394. X     fprintf(stderr, "     -s     follow symbolic links to directories\n");
  395. X     fprintf(stderr, "     -m     follow mount points\n");
  396. X     fprintf(stderr, "     -y     print yield of expunge\n");
  397. X     fprintf(stderr, "     --     end options and start filenames\n");
  398. X}
  399. X
  400. X
  401. X
  402. X
  403. X
  404. Xint expunge(files, num)
  405. Xchar **files;
  406. Xint num;
  407. X{
  408. X     char **found_files;
  409. X     int num_found;
  410. X     int status = 0;
  411. X     int total = 0;
  412. X     filerec *current;
  413. X     int retval;
  414. X     
  415. X     if (initialize_tree())
  416. X      exit(1);
  417. X
  418. X     for ( ; num ; num--) {
  419. X      retval = get_the_files(files[num - 1], &num_found, &found_files);
  420. X      if (retval) {
  421. X           error(files[num - 1]);
  422. X           return retval;
  423. X      }
  424. X           
  425. X      if (num_found) {
  426. X           num_found = process_files(found_files, num_found);
  427. X           if (num_found < 0) {
  428. X            error("process_files");
  429. X            return error_code;
  430. X           }
  431. X      }
  432. X      
  433. X      total += num_found;
  434. X      if (! num_found) if (! force) {
  435. X           /*
  436. X        * There are three different situations here.  Eiter we
  437. X        * are dealing with an existing directory with no
  438. X            * deleted files in it, or we are deleting with a
  439. X            * non-existing deleted file with wildcards, or we are
  440. X            * dealing with a non-existing deleted file without
  441. X            * wildcards.  In the former case we print nothing, and
  442. X            * in the latter cases we print either "no match" or
  443. X            * "not found" respectively
  444. X        */
  445. X           if (no_wildcards(files[num - 1])) {
  446. X            if (! directory_exists(files[num - 1])) {
  447. X             set_error(ENOENT);
  448. X             error(files[num - 1]);
  449. X            }
  450. X           }
  451. X           else {
  452. X            set_error(ENOMATCH);
  453. X            error(files[num - 1]);
  454. X           }
  455. X      }
  456. X     }
  457. X     if (total && listfiles) {
  458. X      if (retval = list_files()) {
  459. X           error("list_files");
  460. X           return retval;
  461. X      }
  462. X      if (! force) if (! top_level()) {
  463. X           set_status(EXPUNGE_NOT_EXPUNGED);
  464. X           return error_code;
  465. X      }
  466. X     }
  467. X     current = get_root_tree();
  468. X     if (current) {
  469. X      if (retval = expunge_specified(current)) {
  470. X           error("expunge_specified");
  471. X           status = retval;
  472. X      }
  473. X     }
  474. X     current = get_cwd_tree();
  475. X     if (current) {
  476. X      if (retval = expunge_specified(current)) {
  477. X           error("expunge_specified");
  478. X           status = retval;
  479. X      }
  480. X     }
  481. X     if (yield) {
  482. X      if (noop)
  483. X           printf("Total that would be expunged: %dk\n",
  484. X              blk_to_k(blocks_removed));
  485. X      else
  486. X           printf("Total expunged: %dk\n", blk_to_k(blocks_removed));
  487. X     }
  488. X     return status;
  489. X}
  490. X
  491. X
  492. X
  493. Xexpunge_specified(leaf)
  494. Xfilerec *leaf;
  495. X{
  496. X     int status = 0;
  497. X     int do_it = 1;
  498. X     int retval;
  499. X     
  500. X     if ((leaf->specified) && ((leaf->specs.st_mode & S_IFMT) == S_IFDIR)) {
  501. X      char buf[MAXPATHLEN];
  502. X
  503. X      if (retval = get_leaf_path(leaf, buf)) {
  504. X           error("get_leaf_path");
  505. X           return retval;
  506. X      }
  507. X      (void) convert_to_user_name(buf, buf);
  508. X
  509. X      if (interactive) {
  510. X           printf("%s: Expunge directory %s? ", whoami, buf);
  511. X           status = (! (do_it = yes()));
  512. X      }
  513. X     }
  514. X     if (do_it) {
  515. X      if (leaf->dirs) {
  516. X           if (retval = expunge_specified(leaf->dirs)) {
  517. X            error("expunge_specified");
  518. X            status = retval;
  519. X           }
  520. X      }
  521. X      if (leaf->files) {
  522. X           if (retval = expunge_specified(leaf->files)) {
  523. X            error("expunge_specified");
  524. X            status = retval;
  525. X           }
  526. X      }
  527. X     }
  528. X     if (leaf->specified && (! status)) {
  529. X      if (retval = really_do_expunge(leaf)) {
  530. X           error("really_do_expunge");
  531. X           status = retval;
  532. X      }
  533. X     }
  534. X     if (leaf->next) {
  535. X      if (retval = expunge_specified(leaf->next)) {
  536. X           error("expunge_specified");
  537. X           status = retval;
  538. X      }
  539. X     }
  540. X
  541. X     free_leaf(leaf);
  542. X     return status;
  543. X}
  544. X
  545. X
  546. Xprocess_files(files, num)
  547. Xchar **files;
  548. Xint num;
  549. X{
  550. X     int i, skipped = 0;
  551. X     filerec *leaf;
  552. X     
  553. X     for (i = 0; i < num; i++) {
  554. X      if (add_path_to_tree(files[i], &leaf)) {
  555. X           error("add_path_to_tree");
  556. X           return -1;
  557. X      }
  558. X      free(files[i]);
  559. X      if (! timed_out(leaf, current_time, timev)) {
  560. X           free_leaf(leaf);
  561. X           skipped++;
  562. X      }
  563. X     }
  564. X     free((char *) files);
  565. X     return(num-skipped);
  566. X}
  567. X
  568. X
  569. X
  570. X
  571. X
  572. X
  573. X
  574. X
  575. X
  576. Xreally_do_expunge(file_ent)
  577. Xfilerec *file_ent;
  578. X{
  579. X     char real[MAXPATHLEN], user[MAXPATHLEN];
  580. X     int status;
  581. X     int retval;
  582. X     
  583. X     if (retval = get_leaf_path(file_ent, real)) {
  584. X      error("get_leaf_path");
  585. X      return retval;
  586. X     }
  587. X     (void) convert_to_user_name(real, user);
  588. X
  589. X     if (interactive) {
  590. X      printf ("%s: Expunge %s (%dk)? ", whoami, user,
  591. X          blk_to_k(file_ent->specs.st_blocks));
  592. X      if (! yes()) {
  593. X           set_status(EXPUNGE_NOT_EXPUNGED);
  594. X           return error_code;
  595. X      }
  596. X     }
  597. X
  598. X     if (noop) {
  599. X      blocks_removed += file_ent->specs.st_blocks;
  600. X      printf("%s: %s (%dk) would be expunged (%dk total)\n", whoami, user,
  601. X         blk_to_k(file_ent->specs.st_blocks),
  602. X         blk_to_k(blocks_removed));
  603. X      return 0;
  604. X     }
  605. X
  606. X     if ((file_ent->specs.st_mode & S_IFMT) == S_IFDIR)
  607. X      status = rmdir(real);
  608. X     else
  609. X      status = unlink(real);
  610. X     if (! status) {
  611. X      blocks_removed += file_ent->specs.st_blocks;
  612. X      if (verbose)
  613. X           printf("%s: %s (%dk) expunged (%dk total)\n", whoami, user,
  614. X              blk_to_k(file_ent->specs.st_blocks),
  615. X              blk_to_k(blocks_removed));
  616. X      return 0;
  617. X     }
  618. X     else {
  619. X      set_error(errno);
  620. X      error(real);
  621. X      return error_code;
  622. X     }
  623. X}
  624. X
  625. X
  626. X
  627. X
  628. X
  629. X
  630. X
  631. X
  632. X
  633. Xtop_level()
  634. X{
  635. X     if (interactive) {
  636. Xprintf("The above files, which have been marked for deletion, are about to be\n");
  637. Xprintf("expunged forever!  You will be asked for confirmation before each file is\n");
  638. Xprintf("deleted.  Do you wish to continue [return = no]? ");
  639. X     }
  640. X     else {
  641. Xprintf("The above files, which have been marked for deletion, are about to be\n");
  642. Xprintf("expunged forever!  Make sure you don't need any of them before continuing.\n");
  643. Xprintf("Do you wish to continue [return = no]? ");
  644. X     }
  645. X     return (yes());
  646. X}
  647. X
  648. X
  649. X
  650. X
  651. X
  652. Xlist_files()
  653. X{
  654. X     filerec *current;
  655. X     char **strings;
  656. X     int num;
  657. X     int retval;
  658. X     
  659. X     strings = (char **) Malloc(sizeof(char *));
  660. X     num = 0;
  661. X     if (! strings) {
  662. X      set_error(errno);
  663. X      error("Malloc");
  664. X      return error_code;
  665. X     }
  666. X
  667. X     printf("The following deleted files are going to be expunged: \n\n");
  668. X
  669. X     current = get_root_tree();
  670. X     if (retval = accumulate_names(current, &strings, &num)) {
  671. X      error("accumulate_names");
  672. X      return retval;
  673. X     }
  674. X     current = get_cwd_tree();
  675. X     if (retval = accumulate_names(current, &strings, &num)) {
  676. X      error("accumulate_names");
  677. X      return retval;
  678. X     }
  679. X     if (retval = column_array(strings, num, DEF_SCR_WIDTH, 0, 0, 2, 1, 0,
  680. X                   1, stdout)) {
  681. X      error("column_array");
  682. X      return retval;
  683. X     }
  684. X     
  685. X     printf("\n");
  686. X     return(0);
  687. X}
  688. X     
  689. X
  690. X
  691. X
  692. X
  693. Xint get_the_files(name, num_found, found)
  694. Xchar *name;
  695. Xint *num_found;
  696. Xchar ***found;
  697. X{
  698. X     int retval;
  699. X     int options;
  700. X     
  701. X     options = FIND_DELETED | FIND_CONTENTS | RECURS_DELETED;
  702. X     if (recursive)
  703. X      options |= RECURS_FIND_DELETED;
  704. X     if (f_mounts)
  705. X      options |= FOLLW_MOUNTPOINTS;
  706. X     if (f_links)
  707. X      options |= FOLLW_LINKS;
  708. X     
  709. X     retval = find_matches(name, num_found, found, options);
  710. X     if (retval) {
  711. X      error("find_matches");
  712. X      return retval;
  713. X     }
  714. X
  715. X     return 0;
  716. X}
  717. END_OF_FILE
  718. if test 11211 -ne `wc -c <'expunge.c'`; then
  719.     echo shar: \"'expunge.c'\" unpacked with wrong size!
  720. fi
  721. # end of 'expunge.c'
  722. fi
  723. if test -f 'lsdel.c' -a "${1}" != "-c" ; then 
  724.   echo shar: Will not clobber existing file \"'lsdel.c'\"
  725. else
  726. echo shar: Extracting \"'lsdel.c'\" \(7280 characters\)
  727. sed "s/^X//" >'lsdel.c' <<'END_OF_FILE'
  728. X/*
  729. X * $Source: /afs/athena.mit.edu/user/j/jik/src/delete/RCS/lsdel.c,v $
  730. X * $Author: jik $
  731. X *
  732. X * This program is a replacement for rm.  Instead of actually deleting
  733. X * files, it marks them for deletion by prefixing them with a ".#"
  734. X * prefix.
  735. X *
  736. X * Copyright (c) 1989 by the Massachusetts Institute of Technology.
  737. X * For copying and distribution information, see the file "mit-copyright.h."
  738. X */
  739. X
  740. X#if (!defined(lint) && !defined(SABER))
  741. X     static char rcsid_lsdel_c[] = "$Header: /afs/athena.mit.edu/user/j/jik/src/delete/RCS/lsdel.c,v 1.9 89/11/22 21:31:08 jik Exp $";
  742. X#endif
  743. X
  744. X#include <stdio.h>
  745. X#include <sys/types.h>
  746. X#include <sys/dir.h>
  747. X#include <sys/param.h>
  748. X#include <sys/stat.h>
  749. X#include <strings.h>
  750. X#include <errno.h>
  751. X#include <com_err.h>
  752. X#include "col.h"
  753. X#include "util.h"
  754. X#include "directories.h"
  755. X#include "pattern.h"
  756. X#include "lsdel.h"
  757. X#include "shell_regexp.h"
  758. X#include "mit-copyright.h"
  759. X#include "delete_errs.h"
  760. X#include "errors.h"
  761. X
  762. Xchar *realloc();
  763. Xextern time_t current_time;
  764. Xextern int errno;
  765. X
  766. Xint block_total = 0;
  767. Xint dirsonly, recursive, yield, f_links, f_mounts;
  768. Xtime_t timev;
  769. X
  770. Xmain(argc, argv)
  771. Xint argc;
  772. Xchar *argv[];
  773. X{
  774. X     extern char *optarg;
  775. X     extern int optind;
  776. X     int arg;
  777. X     
  778. X     whoami = lastpart(argv[0]);
  779. X
  780. X     dirsonly = recursive = timev = yield = f_links = f_mounts = 0;
  781. X     while ((arg = getopt(argc, argv, "drt:ysm")) != -1) {
  782. X      switch (arg) {
  783. X      case 'd':
  784. X           dirsonly++;
  785. X           break;
  786. X      case 'r':
  787. X           recursive++;
  788. X           break;
  789. X      case 't':
  790. X           timev = atoi(optarg);
  791. X           break;
  792. X      case 'y':
  793. X           yield++;
  794. X           break;
  795. X      case 's':
  796. X           f_links++;
  797. X           break;
  798. X      case 'm':
  799. X           f_mounts++;
  800. X           break;
  801. X      default:
  802. X           usage();
  803. X           exit(1);
  804. X      }
  805. X     }
  806. X     if (optind == argc) {
  807. X      char *cwd;
  808. X
  809. X      cwd = ".";
  810. X
  811. X      if (ls(&cwd, 1))
  812. X           error("ls of .");
  813. X     }
  814. X     else if (ls(&argv[optind], argc - optind))
  815. X      error ("ls");
  816. X
  817. X     exit (error_occurred ? 1 : 0);
  818. X}
  819. X
  820. X
  821. X
  822. X
  823. X
  824. X
  825. Xusage()
  826. X{
  827. X     fprintf(stderr, "Usage: %s [ options ] [ filename [ ...]]\n", whoami);
  828. X     fprintf(stderr, "Options are:\n");
  829. X     fprintf(stderr, "     -d     list directory names, not contents\n");
  830. X     fprintf(stderr, "     -r     recursive\n");
  831. X     fprintf(stderr, "     -t n   list n-day-or-older files only\n");
  832. X     fprintf(stderr, "     -y     report total space taken up by files\n");
  833. X     fprintf(stderr, "     -s     follow symbolic links to directories\n");
  834. X     fprintf(stderr, "     -m     follow mount points\n");
  835. X}
  836. X
  837. X
  838. X
  839. X
  840. Xls(args, num)
  841. Xchar **args;
  842. Xint num;
  843. X{
  844. X     char **found_files;
  845. X     int num_found = 0, total = 0;
  846. X     int status = 0;
  847. X     int retval;
  848. X
  849. X     initialize_del_error_table();
  850. X     
  851. X     if (retval = initialize_tree()) {
  852. X      error("initialize_tree");
  853. X      return retval;
  854. X     }
  855. X     
  856. X     for ( ; num; num--) {
  857. X      if (retval = get_the_files(args[num - 1], &num_found,
  858. X                     &found_files)) {
  859. X           error(args[num - 1]);
  860. X           status = retval;
  861. X           continue;
  862. X      }
  863. X
  864. X      if (num_found) {
  865. X           num_found = process_files(found_files, num_found);
  866. X           if (num_found < 0) {
  867. X            error("process_files");
  868. X            status = error_code;
  869. X            continue;
  870. X           }
  871. X           total += num_found;
  872. X      }
  873. X      else {
  874. X           /* What we do at this point depends on exactly what the
  875. X            * filename is.  There are several possible conditions:
  876. X        * 1. The filename has no wildcards in it, which means that
  877. X        *    if we couldn't find it, that means it doesn't
  878. X        *    exist.  Print a not found error.
  879. X        * 2. Filename is an existing directory, with no deleted
  880. X        *    files in it.  Print nothing.
  881. X        * 3. Filename doesn't exist, and there are wildcards in
  882. X        *    it.  Print "no match".
  883. X        * None of these are considered error conditions, so we
  884. X        * don't set the error flag.
  885. X        */
  886. X           if (no_wildcards(args[num - 1])) {
  887. X            if (! directory_exists(args[num - 1])) {
  888. X             set_error(ENOENT);
  889. X             error(args[num - 1]);
  890. X             status = error_code;
  891. X             continue;
  892. X            }
  893. X           }
  894. X           else {
  895. X            set_error(ENOMATCH);
  896. X            error(args[num - 1]);
  897. X            status = error_code;
  898. X            continue;
  899. X           }
  900. X      }
  901. X     }
  902. X     if (total) {
  903. X      if (list_files()) {
  904. X           error("list_files");
  905. X           return error_code;
  906. X      }
  907. X     }
  908. X     if (yield)
  909. X      printf("\nTotal space taken up by file%s: %dk\n",
  910. X         (total == 1 ? "" : "s"), blk_to_k(block_total));
  911. X
  912. X     return status;
  913. X}
  914. X
  915. X
  916. X
  917. X
  918. Xint get_the_files(name, number_found, found)
  919. Xchar *name;
  920. Xint *number_found;
  921. Xchar ***found;
  922. X{
  923. X     int retval;
  924. X     int options;
  925. X     
  926. X     options = FIND_DELETED | FIND_CONTENTS;
  927. X     if (recursive)
  928. X      options |= RECURS_FIND_DELETED;
  929. X     if (! dirsonly)
  930. X      options |= RECURS_DELETED;
  931. X     if (f_mounts)
  932. X      options |= FOLLW_MOUNTPOINTS;
  933. X     if (f_links)
  934. X      options |= FOLLW_LINKS;
  935. X     
  936. X     retval = find_matches(name, number_found, found, options);
  937. X     if (retval) {
  938. X      error("find_matches");
  939. X      return retval;
  940. X     }
  941. X
  942. X     return 0;
  943. X}
  944. X
  945. X
  946. X
  947. X
  948. X
  949. X
  950. Xprocess_files(files, num)
  951. Xchar **files;
  952. Xint num;
  953. X{
  954. X     int i;
  955. X     filerec *leaf;
  956. X     
  957. X     for (i = 0; i < num; i++) {
  958. X      if (add_path_to_tree(files[i], &leaf)) {
  959. X           error("add_path_to_tree");
  960. X           return -1;
  961. X      }
  962. X      free(files[i]);
  963. X      if (! timed_out(leaf, current_time, timev)) {
  964. X           free_leaf(leaf);
  965. X           num--;
  966. X           continue;
  967. X      }
  968. X      block_total += leaf->specs.st_blocks;
  969. X     }
  970. X     free((char *) files);
  971. X     return(num);
  972. X}
  973. X
  974. X
  975. X
  976. X
  977. X
  978. Xlist_files()
  979. X{
  980. X     filerec *current;
  981. X     char **strings;
  982. X     int num;
  983. X     int retval;
  984. X     
  985. X     strings = (char **) Malloc((unsigned) sizeof(char *));
  986. X     num = 0;
  987. X     if (! strings) {
  988. X      set_error(errno);
  989. X      error("Malloc");
  990. X      return error_code;
  991. X     }
  992. X     current = get_root_tree();
  993. X     if (retval = accumulate_names(current, &strings, &num)) {
  994. X      error("accumulate_names");
  995. X      return retval;
  996. X     }
  997. X     current = get_cwd_tree();
  998. X     if (retval = accumulate_names(current, &strings, &num)) {
  999. X      error("accumulate_names");
  1000. X      return retval;
  1001. X     }
  1002. X
  1003. X     if (retval = sort_files(strings, num)) {
  1004. X      error("sort_files");
  1005. X      return retval;
  1006. X     }
  1007. X     
  1008. X     if (retval = unique(&strings, &num)) {
  1009. X      error("unique");
  1010. X      return retval;
  1011. X     }
  1012. X     
  1013. X     if (retval = column_array(strings, num, DEF_SCR_WIDTH, 0, 0, 2, 1, 0,
  1014. X                   1, stdout)) {
  1015. X      error("column_array");
  1016. X      return retval;
  1017. X     }
  1018. X     
  1019. X     for ( ; num; num--)
  1020. X      free(strings[num - 1]);
  1021. X     free((char *) strings);
  1022. X     return 0;
  1023. X}
  1024. X
  1025. X
  1026. Xint sort_files(data, num_data)
  1027. Xchar **data;
  1028. Xint num_data;
  1029. X{
  1030. X     qsort((char *) data, num_data, sizeof(char *), strcmp);
  1031. X
  1032. X     return 0;
  1033. X}
  1034. X
  1035. X
  1036. Xint unique(the_files, number)
  1037. Xchar ***the_files;
  1038. Xint *number;
  1039. X{
  1040. X     int i, last;
  1041. X     int offset;
  1042. X     char **files;
  1043. X
  1044. X     files = *the_files;
  1045. X     for (last = 0, i = 1; i < *number; i++) {
  1046. X      if (! strcmp(files[last], files[i])) {
  1047. X           free (files[i]);
  1048. X           free (files[i]);
  1049. X           files[i] = (char *) NULL;
  1050. X      }
  1051. X      else
  1052. X           last = i;
  1053. X     }
  1054. X     
  1055. X     for (offset = 0, i = 0; i + offset < *number; i++) {
  1056. X      if (! files[i])
  1057. X           offset++;
  1058. X      if (i + offset < *number)
  1059. X           files[i] = files[i + offset];
  1060. X     }
  1061. X     *number -= offset;
  1062. X     files = (char **) realloc((char *) files,
  1063. X                   (unsigned) (sizeof(char *) * *number));
  1064. X     if (! files) {
  1065. X      set_error(errno);
  1066. X      error("realloc");
  1067. X      return errno;
  1068. X     }
  1069. X
  1070. X     *the_files = files;
  1071. X     return 0;
  1072. X}
  1073. END_OF_FILE
  1074. if test 7280 -ne `wc -c <'lsdel.c'`; then
  1075.     echo shar: \"'lsdel.c'\" unpacked with wrong size!
  1076. fi
  1077. # end of 'lsdel.c'
  1078. fi
  1079. if test -f 'undelete.c' -a "${1}" != "-c" ; then 
  1080.   echo shar: Will not clobber existing file \"'undelete.c'\"
  1081. else
  1082. echo shar: Extracting \"'undelete.c'\" \(12500 characters\)
  1083. sed "s/^X//" >'undelete.c' <<'END_OF_FILE'
  1084. X/*
  1085. X * $Source: /afs/athena.mit.edu/user/j/jik/src/delete/RCS/undelete.c,v $
  1086. X * $Author: jik $
  1087. X *
  1088. X * This program is part of a package including delete, undelete,
  1089. X * lsdel, expunge and purge.  The software suite is meant as a
  1090. X * replacement for rm which allows for file recovery.
  1091. X * 
  1092. X * Copyright (c) 1989 by the Massachusetts Institute of Technology.
  1093. X * For copying and distribution information, see the file "mit-copyright.h."
  1094. X */
  1095. X
  1096. X#if (!defined(lint) && !defined(SABER))
  1097. X     static char rcsid_undelete_c[] = "$Header: /afs/athena.mit.edu/user/j/jik/src/delete/RCS/undelete.c,v 1.19 89/12/15 04:39:31 jik Exp $";
  1098. X#endif
  1099. X
  1100. X#include <stdio.h>
  1101. X#include <sys/types.h>
  1102. X#include <sys/dir.h>
  1103. X#include <sys/param.h>
  1104. X#include <strings.h>
  1105. X#include <sys/stat.h>
  1106. X#include <com_err.h>
  1107. X#include <errno.h>
  1108. X#include "delete_errs.h"
  1109. X#include "directories.h"
  1110. X#include "pattern.h"
  1111. X#include "util.h"
  1112. X#include "undelete.h"
  1113. X#include "shell_regexp.h"
  1114. X#include "mit-copyright.h"
  1115. X#include "errors.h"
  1116. X
  1117. Xextern char *realloc();
  1118. Xextern int errno;
  1119. X
  1120. Xint interactive, recursive, verbose, directoriesonly, noop, force;
  1121. X
  1122. X
  1123. Xmain(argc, argv)
  1124. Xint argc;
  1125. Xchar *argv[];
  1126. X{
  1127. X     extern char *optarg;
  1128. X     extern int optind;
  1129. X     int arg;
  1130. X     int retval;
  1131. X     
  1132. X     initialize_del_error_table();
  1133. X     
  1134. X     whoami = lastpart(argv[0]);
  1135. X     interactive = recursive = verbose = directoriesonly = noop = force = 0;
  1136. X
  1137. X     while ((arg = getopt(argc, argv, "firvnR")) != -1) {
  1138. X      switch (arg) {
  1139. X      case 'f':
  1140. X           force++;
  1141. X           break;
  1142. X      case 'i':
  1143. X           interactive++;
  1144. X           break;
  1145. X      case 'r':
  1146. X           recursive++;
  1147. X           if (directoriesonly) {
  1148. X            fprintf(stderr, "%s: -r and -R and mutually exclusive.\n",
  1149. X                whoami);
  1150. X            usage();
  1151. X            exit(1);
  1152. X           }
  1153. X           break;
  1154. X      case 'v':
  1155. X           verbose++;
  1156. X           break;
  1157. X      case 'n':
  1158. X           noop++;
  1159. X           break;
  1160. X      case 'R':
  1161. X           directoriesonly++;
  1162. X           if (recursive) {
  1163. X            fprintf(stderr, "%s: -r and -R are mutually exclusive.\n",
  1164. X                whoami);
  1165. X            usage();
  1166. X            exit(1);
  1167. X           }
  1168. X           break;
  1169. X      default:
  1170. X           usage();
  1171. X           exit(1);
  1172. X      }
  1173. X     }
  1174. X
  1175. X     report_errors = ! force;
  1176. X     
  1177. X     if (optind == argc) {
  1178. X      if (interactive_mode())
  1179. X           error("interactive_mode");
  1180. X     }
  1181. X     else while (optind < argc) {
  1182. X      retval = undelete(argv[optind]);
  1183. X      if (retval)
  1184. X           error(argv[optind]);
  1185. X      optind++;
  1186. X     }
  1187. X     exit(((! force) && error_occurred) ? 1 : 0);
  1188. X}
  1189. X
  1190. X
  1191. X
  1192. Xinteractive_mode()
  1193. X{
  1194. X     char buf[MAXPATHLEN];
  1195. X     char *ptr;
  1196. X     int status = 0;
  1197. X     int retval;
  1198. X     
  1199. X     if (verbose) {
  1200. X      printf("Enter the files to be undeleted, one file per line.\n");
  1201. X      printf("Hit <RETURN> on a line by itself to exit.\n\n");
  1202. X     }
  1203. X     do {
  1204. X      printf("%s: ", whoami);
  1205. X      ptr = fgets(buf, MAXPATHLEN, stdin);
  1206. X      if (! ptr) {
  1207. X           printf("\n");
  1208. X           return status;
  1209. X      }
  1210. X      ptr = index(buf, '\n');  /* fgets breakage */
  1211. X      if (ptr)
  1212. X           *ptr = '\0';
  1213. X      if (! *buf)
  1214. X           return status;
  1215. X      retval = undelete(buf);
  1216. X      if (retval) {
  1217. X           error(buf);
  1218. X           status = retval;
  1219. X      }
  1220. X     } while (*buf);
  1221. X     return status;
  1222. X}
  1223. X
  1224. X
  1225. X
  1226. Xusage()
  1227. X{
  1228. X     fprintf(stderr, "Usage: %s [ options ] [filename ...]\n", whoami);
  1229. X     fprintf(stderr, "Options are:\n");
  1230. X     fprintf(stderr, "     -r     recursive\n");
  1231. X     fprintf(stderr, "     -i     interactive\n");
  1232. X     fprintf(stderr, "     -f     force\n");
  1233. X     fprintf(stderr, "     -v     verbose\n");
  1234. X     fprintf(stderr, "     -n     noop\n");
  1235. X     fprintf(stderr, "     -R     directories only (i.e. no recursion)\n");
  1236. X     fprintf(stderr, "     --     end options and start filenames\n");
  1237. X     fprintf(stderr, "-r and -D are mutually exclusive\n");
  1238. X}
  1239. X
  1240. Xundelete(name)
  1241. Xchar *name;
  1242. X{
  1243. X     char **found_files;
  1244. X     int num_found;
  1245. X     int status = 0;
  1246. X     filerec *current;
  1247. X     int retval;
  1248. X     
  1249. X     if (retval =  get_the_files(name, &num_found, &found_files)) {
  1250. X      error(name);
  1251. X      return retval;
  1252. X     }
  1253. X     
  1254. X     if (num_found) {
  1255. X      if (retval = process_files(found_files, num_found)) {
  1256. X           error(name);
  1257. X           return retval;
  1258. X      }
  1259. X      if (*name == '/')
  1260. X           current = get_root_tree();
  1261. X      else
  1262. X           current = get_cwd_tree();
  1263. X
  1264. X      status = recurs_and_undelete(current);
  1265. X      if (status) {
  1266. X           error(name);
  1267. X           return status;
  1268. X      }
  1269. X     }
  1270. X     else {
  1271. X      if (no_wildcards(name)) {
  1272. X           set_error(ENOENT)
  1273. X      }
  1274. X      else
  1275. X           set_error(ENOMATCH);
  1276. X      error(name);
  1277. X      return error_code;
  1278. X     }
  1279. X
  1280. X     return status;
  1281. X}
  1282. X
  1283. X
  1284. X
  1285. X
  1286. X
  1287. Xint recurs_and_undelete(leaf)
  1288. Xfilerec *leaf;
  1289. X{
  1290. X     int status = 0;
  1291. X     int retval;
  1292. X     
  1293. X     if (leaf->specified) {
  1294. X      retval = do_undelete(leaf);
  1295. X      if (retval) {
  1296. X           error("do_undelete");
  1297. X           return retval;
  1298. X      }
  1299. X     }
  1300. X
  1301. X     if (leaf->dirs) {
  1302. X      retval = recurs_and_undelete(leaf->dirs);
  1303. X      if (retval) {
  1304. X           error("recurs_and_undelete");
  1305. X           status = retval;
  1306. X      }
  1307. X     }
  1308. X
  1309. X     if (leaf->files) {
  1310. X      retval = recurs_and_undelete(leaf->files);
  1311. X      if (retval) {
  1312. X           error("recurs_and_undelete");
  1313. X           status = retval;
  1314. X      }
  1315. X     }
  1316. X     
  1317. X     if (leaf->next) {
  1318. X      retval = recurs_and_undelete(leaf->next);
  1319. X      if (retval) {
  1320. X           error("recurs_and_undelete");
  1321. X           status = retval;
  1322. X      }
  1323. X     }
  1324. X     
  1325. X     free_leaf(leaf);
  1326. X
  1327. X     return status;
  1328. X}
  1329. X
  1330. X
  1331. X
  1332. X
  1333. X
  1334. X
  1335. Xint process_files(files, num)
  1336. Xchar **files;
  1337. Xint num;
  1338. X{
  1339. X     int i;
  1340. X     listrec *filelist;
  1341. X     struct filrec *not_needed;
  1342. X     int retval;
  1343. X     
  1344. X     filelist = (listrec *) Malloc((unsigned) (sizeof(listrec) * num));
  1345. X     if (! filelist) {
  1346. X      set_error(errno);
  1347. X      error("process_files");
  1348. X      return error_code;
  1349. X     }
  1350. X     
  1351. X     for (i = 0; i < num; i++) {
  1352. X      filelist[i].real_name = Malloc((unsigned) (strlen(files[i]) + 1));
  1353. X      if (! filelist[i].real_name) {
  1354. X           set_error(errno);
  1355. X           error("process_files");
  1356. X           return error_code;
  1357. X      }
  1358. X      (void) strcpy(filelist[i].real_name, files[i]);
  1359. X      filelist[i].user_name = Malloc((unsigned) (strlen(files[i]) + 1));
  1360. X      if (! filelist[i].user_name) {
  1361. X           set_error(errno);
  1362. X           error("process_files");
  1363. X           return error_code;
  1364. X      }
  1365. X       (void) convert_to_user_name(files[i], filelist[i].user_name);
  1366. X      free(files[i]);
  1367. X     }
  1368. X     free((char *) files);
  1369. X      
  1370. X     if (retval = sort_files(filelist, num)) {
  1371. X      error("sort_files");
  1372. X      return retval;
  1373. X     }
  1374. X     if (retval = unique(&filelist, &num)) {
  1375. X      error("unique");
  1376. X      return retval;
  1377. X     }
  1378. X     if (retval = initialize_tree()) {
  1379. X      error("initialize_tree");
  1380. X      return retval;
  1381. X     }
  1382. X      
  1383. X     for (i = 0; i < num; i++) {
  1384. X      if (retval = add_path_to_tree(filelist[i].real_name, ¬_needed)) {
  1385. X           error("add_path_to_tree");
  1386. X           return retval;
  1387. X      }
  1388. X      else {
  1389. X           free(filelist[i].real_name);
  1390. X           free(filelist[i].user_name);
  1391. X      }
  1392. X     }
  1393. X     free((char *) filelist);
  1394. X     return 0;
  1395. X}
  1396. X
  1397. X     
  1398. X
  1399. X
  1400. X
  1401. X
  1402. X
  1403. X     
  1404. Xdo_undelete(file_ent)
  1405. Xfilerec *file_ent;
  1406. X{
  1407. X     struct stat stat_buf;
  1408. X     char user_name[MAXPATHLEN], real_name[MAXPATHLEN];
  1409. X     int retval;
  1410. X     
  1411. X     if (retval = get_leaf_path(file_ent, real_name)) {
  1412. X      if (! force)
  1413. X           fprintf(stderr, "%s: %s: %s\n", whoami, "get_leaf_path",
  1414. X               error_message(retval));
  1415. X      return retval;
  1416. X     }
  1417. X     
  1418. X     (void) convert_to_user_name(real_name, user_name);
  1419. X
  1420. X     if (interactive) {
  1421. X      if ((file_ent->specs.st_mode & S_IFMT) == S_IFDIR)
  1422. X           printf("%s: Undelete directory %s? ", whoami, user_name);
  1423. X      else
  1424. X           printf("%s: Undelete %s? ", whoami, user_name);
  1425. X      if (! yes()) {
  1426. X           set_status(UNDEL_NOT_UNDELETED);
  1427. X           return error_code;
  1428. X      }
  1429. X     }
  1430. X     if (! lstat(user_name, &stat_buf)) if (! force) {
  1431. X      printf("%s: An undeleted %s already exists.\n", whoami, user_name);
  1432. X      printf("Do you wish to continue with the undelete and overwrite that version? ");
  1433. X      if (! yes()) {
  1434. X           set_status(UNDEL_NOT_UNDELETED);
  1435. X           return error_code;
  1436. X      }
  1437. X      if (! noop) if (retval = unlink_completely(user_name)) {
  1438. X           error(user_name);
  1439. X           return retval;
  1440. X      }
  1441. X     }
  1442. X     if (noop) {
  1443. X      printf("%s: %s would be undeleted\n", whoami, user_name);
  1444. X      return 0;
  1445. X     }
  1446. X
  1447. X     if (retval = do_file_rename(real_name, user_name)) {
  1448. X      error("do_file_rename");
  1449. X      return retval;
  1450. X     }
  1451. X     else {
  1452. X      if (verbose)
  1453. X           printf("%s: %s undeleted\n", whoami, user_name);
  1454. X      return 0;
  1455. X     }
  1456. X}
  1457. X
  1458. X
  1459. X
  1460. X
  1461. Xdo_file_rename(real_name, user_name)
  1462. Xchar *real_name, *user_name;
  1463. X{
  1464. X     char *ptr;
  1465. X     int retval;
  1466. X     char error_buf[MAXPATHLEN+MAXPATHLEN+14];
  1467. X     char old_name[MAXPATHLEN], new_name[MAXPATHLEN];
  1468. X     char buf[MAXPATHLEN];
  1469. X
  1470. X     (void) strcpy(old_name, real_name);
  1471. X     (void) strcpy(new_name, real_name);
  1472. X
  1473. X     while (ptr = strrindex(new_name, ".#")) {
  1474. X      (void) convert_to_user_name(ptr, ptr);
  1475. X      (void) strcpy(ptr, firstpart(ptr, buf));
  1476. X      (void) strcpy(&old_name[ptr - new_name],
  1477. X            firstpart(&old_name[ptr - new_name], buf));
  1478. X      if (rename(old_name, new_name)) {
  1479. X           set_error(errno);
  1480. X           (void) sprintf(error_buf, "renaming %s to %s",
  1481. X                  old_name, new_name);
  1482. X           error(error_buf);
  1483. X           return error_code;
  1484. X      }
  1485. X      if (ptr > new_name) {
  1486. X           *--ptr = '\0';
  1487. X           old_name[ptr - new_name] = '\0';
  1488. X      }
  1489. X     }
  1490. X     if (retval = change_path(real_name, user_name)) {
  1491. X      error("change_path");
  1492. X      return retval;
  1493. X     }
  1494. X     
  1495. X     return 0;
  1496. X}
  1497. X
  1498. X
  1499. X
  1500. X
  1501. X
  1502. X
  1503. Xfilecmp(file1, file2)
  1504. Xlistrec *file1, *file2;
  1505. X{
  1506. X     return(strcmp(file1->user_name, file2->user_name));
  1507. X}
  1508. X
  1509. X     
  1510. X     
  1511. Xint sort_files(data, num_data)
  1512. Xlistrec *data;
  1513. Xint num_data;
  1514. X{
  1515. X     qsort((char *) data, num_data, sizeof(listrec), filecmp);
  1516. X
  1517. X     return 0;
  1518. X}
  1519. X
  1520. X
  1521. X
  1522. X
  1523. X
  1524. Xint unique(the_files, number)
  1525. Xlistrec **the_files;
  1526. Xint *number;
  1527. X{
  1528. X     int i, last;
  1529. X     int offset;
  1530. X     listrec *files;
  1531. X
  1532. X     files = *the_files;
  1533. X     for (last = 0, i = 1; i < *number; i++) {
  1534. X      if (! strcmp(files[last].user_name, files[i].user_name)) {
  1535. X           int better;
  1536. X
  1537. X           better = choose_better(files[last].real_name,
  1538. X                      files[i].real_name);
  1539. X           if (better == 1) { /* the first one is better */
  1540. X            free (files[i].real_name);
  1541. X            free (files[i].user_name);
  1542. X            files[i].real_name = (char *) NULL;
  1543. X           }
  1544. X           else {
  1545. X            free (files[last].real_name);
  1546. X            free (files[last].user_name);
  1547. X            files[last].real_name = (char *) NULL;
  1548. X            last = i;
  1549. X           }
  1550. X      }
  1551. X      else
  1552. X           last = i;
  1553. X     }
  1554. X     
  1555. X     for (offset = 0, i = 0; i + offset < *number; i++) {
  1556. X      if (! files[i].real_name)
  1557. X           offset++;
  1558. X      if (i + offset < *number)
  1559. X           files[i] = files[i + offset];
  1560. X     }
  1561. X     *number -= offset;
  1562. X     files = (listrec *) realloc((char *) files,
  1563. X                 (unsigned) (sizeof(listrec) * *number));
  1564. X     if (! files) {
  1565. X      set_error(errno);
  1566. X      error("realloc");
  1567. X      return errno;
  1568. X     }
  1569. X
  1570. X     *the_files = files;
  1571. X     return 0;
  1572. X}
  1573. X
  1574. X
  1575. X
  1576. X
  1577. Xchoose_better(str1, str2)
  1578. Xchar *str1, *str2;
  1579. X{
  1580. X     char *pos1, *pos2;
  1581. X     
  1582. X     pos1 = strindex(str1, ".#");
  1583. X     pos2 = strindex(str2, ".#");
  1584. X     while (pos1 && pos2) {
  1585. X      if (pos1 - str1 < pos2 - str2)
  1586. X           return(2);
  1587. X      else if (pos2 - str2 < pos1 - str1)
  1588. X           return(1);
  1589. X      pos1 = strindex(pos1 + 1, ".#");
  1590. X      pos2 = strindex(pos2 + 1, ".#");
  1591. X     }
  1592. X     if (! pos1)
  1593. X      return(1);
  1594. X     else
  1595. X      return(2);
  1596. X}
  1597. X
  1598. X
  1599. X
  1600. X
  1601. X     
  1602. Xunlink_completely(filename)
  1603. Xchar *filename;
  1604. X{
  1605. X     char buf[MAXPATHLEN];
  1606. X     struct stat stat_buf;
  1607. X     DIR *dirp;
  1608. X     struct direct *dp;
  1609. X     int retval;
  1610. X     int status = 0;
  1611. X     
  1612. X     if (lstat(filename, &stat_buf)) {
  1613. X      set_error(errno);
  1614. X      error(filename);
  1615. X      return error_code;
  1616. X     }
  1617. X
  1618. X     if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
  1619. X      dirp = Opendir(filename);
  1620. X      if (! dirp) {
  1621. X           set_error(errno);
  1622. X           error(filename);
  1623. X           return error_code;
  1624. X      }
  1625. X           
  1626. X      for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
  1627. X           if (is_dotfile(dp->d_name))
  1628. X            continue;
  1629. X           (void) strcpy(buf, append(filename, dp->d_name));
  1630. X           if (retval = unlink_completely(buf)) {
  1631. X            error(buf);
  1632. X            status = retval;
  1633. X           }
  1634. X      }
  1635. X      closedir(dirp);
  1636. X      if (retval = rmdir(filename)) {
  1637. X           set_error(errno);
  1638. X           error(filename);
  1639. X           return error_code;
  1640. X      }
  1641. X     }
  1642. X     else if (retval = unlink(filename)) {
  1643. X      set_error(errno);
  1644. X      error(filename);
  1645. X      return error_code;
  1646. X     }
  1647. X
  1648. X     return status;
  1649. X}
  1650. X
  1651. X
  1652. X
  1653. X
  1654. Xint get_the_files(name, num_found, found)
  1655. Xchar *name;
  1656. Xint *num_found;
  1657. Xchar ***found;
  1658. X{
  1659. X     int retval;
  1660. X     int options;
  1661. X     
  1662. X     options = FIND_DELETED;
  1663. X     if (recursive)
  1664. X      options |= RECURS_DELETED;
  1665. X     if (! directoriesonly)
  1666. X      options |= FIND_CONTENTS;
  1667. X
  1668. X     retval = find_matches(name, num_found, found, options);
  1669. X     if (retval) {
  1670. X      error("find_matches");
  1671. X      return retval;
  1672. X     }
  1673. X
  1674. X     return 0;
  1675. X}
  1676. END_OF_FILE
  1677. if test 12500 -ne `wc -c <'undelete.c'`; then
  1678.     echo shar: \"'undelete.c'\" unpacked with wrong size!
  1679. fi
  1680. # end of 'undelete.c'
  1681. fi
  1682. if test -f 'util.c' -a "${1}" != "-c" ; then 
  1683.   echo shar: Will not clobber existing file \"'util.c'\"
  1684. else
  1685. echo shar: Extracting \"'util.c'\" \(7849 characters\)
  1686. sed "s/^X//" >'util.c' <<'END_OF_FILE'
  1687. X/*
  1688. X * $Source: /afs/athena.mit.edu/user/j/jik/src/delete/RCS/util.c,v $
  1689. X * $Author: jik $
  1690. X *
  1691. X * This program is a replacement for rm.  Instead of actually deleting
  1692. X * files, it marks them for deletion by prefixing them with a ".#"
  1693. X * prefix.
  1694. X *
  1695. X * Copyright (c) 1989 by the Massachusetts Institute of Technology.
  1696. X * For copying and distribution information, see the file "mit-copyright.h."
  1697. X */
  1698. X
  1699. X#if (!defined(lint) && !defined(SABER))
  1700. X     static char rcsid_util_c[] = "$Header: /afs/athena.mit.edu/user/j/jik/src/delete/RCS/util.c,v 1.15 90/01/11 03:47:11 jik Exp $";
  1701. X#endif
  1702. X
  1703. X#include <stdio.h>
  1704. X#include <sys/param.h>
  1705. X#include <sys/types.h>
  1706. X#include <sys/stat.h>
  1707. X#include <sys/dir.h>
  1708. X#include <strings.h>
  1709. X#include <pwd.h>
  1710. X#include <errno.h>
  1711. X#ifdef AFS_MOUNTPOINTS
  1712. X#include <sys/ioctl.h>
  1713. X#include <afs/vice.h>
  1714. X#include <afs/venus.h>
  1715. X#endif
  1716. X#include "delete_errs.h"
  1717. X#include "directories.h"
  1718. X#include "util.h"
  1719. X#include "mit-copyright.h"
  1720. X#include "errors.h"
  1721. X
  1722. Xextern char *getenv();
  1723. Xextern uid_t getuid();
  1724. Xextern int errno;
  1725. X
  1726. Xchar *convert_to_user_name(real_name, user_name)
  1727. Xchar real_name[];
  1728. Xchar user_name[];  /* RETURN */
  1729. X{
  1730. X     char *ptr, *q;
  1731. X     
  1732. X     (void) strcpy(user_name, real_name);
  1733. X     while (ptr = strrindex(user_name, ".#")) {
  1734. X      for (q = ptr; *(q + 2); q++)
  1735. X           *q = *(q + 2);
  1736. X      *q = '\0';
  1737. X     }
  1738. X     return (user_name);
  1739. X}
  1740. X
  1741. X     
  1742. X
  1743. X
  1744. X
  1745. Xchar *strindex(str, sub_str)
  1746. Xchar *str, *sub_str;
  1747. X{
  1748. X     char *ptr = str;
  1749. X     while (ptr = index(ptr, *sub_str)) {
  1750. X      if (! strncmp(ptr, sub_str, strlen(sub_str)))
  1751. X           return(ptr);
  1752. X      ptr++;
  1753. X     }
  1754. X     return ((char *) NULL);
  1755. X}
  1756. X
  1757. X
  1758. X
  1759. Xchar *strrindex(str, sub_str)
  1760. Xchar *str, *sub_str;
  1761. X{
  1762. X     char *ptr;
  1763. X
  1764. X     if (strlen(str))
  1765. X      ptr = &str[strlen(str) - 1];
  1766. X     else
  1767. X      return((char *) NULL);
  1768. X     while ((*ptr != *sub_str) && (ptr != str)) ptr--;
  1769. X     while (ptr != str) {
  1770. X      if (! strncmp(ptr, sub_str, strlen(sub_str)))
  1771. X           return(ptr);
  1772. X      ptr--;
  1773. X      while ((*ptr != *sub_str) && (ptr != str)) ptr--;
  1774. X     }
  1775. X     if (! strncmp(ptr, sub_str, strlen(sub_str)))
  1776. X      return(str);
  1777. X     else
  1778. X      return ((char *) NULL);
  1779. X}
  1780. X     
  1781. X     
  1782. X/*
  1783. X * NOTE: Append uses a static array, so its return value must be
  1784. X * copied immediately.
  1785. X */
  1786. Xchar *append(filepath, filename)
  1787. Xchar *filepath, *filename;
  1788. X{
  1789. X     static char buf[MAXPATHLEN];
  1790. X
  1791. X     (void) strcpy(buf, filepath);
  1792. X     if ((! *filename) || (! *filepath)) {
  1793. X      (void) strcpy(buf, filename);
  1794. X      return(buf);
  1795. X     }
  1796. X     if (buf[strlen(buf) - 1] == '/')
  1797. X      buf[strlen(buf) - 1] = '\0';
  1798. X     if (strlen(buf) + strlen(filename) + 2 > MAXPATHLEN) {
  1799. X      set_error(ENAMETOOLONG);
  1800. X      strncat(buf, "/", MAXPATHLEN - strlen(buf) - 1);
  1801. X      strncat(buf, filename, MAXPATHLEN - strlen(buf) - 1);
  1802. X      error(buf);
  1803. X       *buf = '\0';
  1804. X      return buf;
  1805. X     }
  1806. X     (void) strcat(buf, "/");
  1807. X     (void) strcat(buf, filename);
  1808. X     return buf;
  1809. X}
  1810. X
  1811. X
  1812. X
  1813. X
  1814. Xyes() {
  1815. X     char buf[BUFSIZ];
  1816. X     char *val;
  1817. X     
  1818. X     val = fgets(buf, BUFSIZ, stdin);
  1819. X     if (! val) {
  1820. X      printf("\n");
  1821. X      exit(1);
  1822. X     }
  1823. X     if (! index(buf, '\n')) do
  1824. X      (void) fgets(buf + 1, BUFSIZ - 1, stdin);
  1825. X     while (! index(buf + 1, '\n'));
  1826. X     return(*buf == 'y');
  1827. X}
  1828. X
  1829. X
  1830. X
  1831. X
  1832. Xchar *lastpart(filename)
  1833. Xchar *filename;
  1834. X{
  1835. X     char *part;
  1836. X
  1837. X     part = rindex(filename, '/');
  1838. X
  1839. X     if (! part)
  1840. X      part = filename;
  1841. X     else if (part == filename)
  1842. X      part++;
  1843. X     else if (part - filename + 1 == strlen(filename)) {
  1844. X      part = rindex(--part, '/');
  1845. X      if (! part)
  1846. X           part = filename;
  1847. X      else
  1848. X           part++;
  1849. X     }
  1850. X     else
  1851. X      part++;
  1852. X
  1853. X     return(part);
  1854. X}
  1855. X
  1856. X
  1857. X
  1858. X
  1859. Xchar *firstpart(filename, rest)
  1860. Xchar *filename;
  1861. Xchar *rest; /* RETURN */
  1862. X{
  1863. X     char *part;
  1864. X     static char buf[MAXPATHLEN];
  1865. X
  1866. X     (void) strcpy(buf, filename);
  1867. X     part = index(buf, '/');
  1868. X     if (! part) {
  1869. X      *rest = '\0';
  1870. X      return(buf);
  1871. X     }
  1872. X     (void) strcpy(rest, part + 1);
  1873. X     *part = '\0';
  1874. X     return(buf);
  1875. X}
  1876. X
  1877. X
  1878. X
  1879. X
  1880. X
  1881. Xget_home(buf)
  1882. Xchar *buf;
  1883. X{
  1884. X     char *user;
  1885. X     struct passwd *psw;
  1886. X     
  1887. X     (void) strcpy(buf, getenv("HOME"));
  1888. X     
  1889. X     if (*buf)
  1890. X      return(0);
  1891. X
  1892. X     user = getenv("USER");
  1893. X     psw = getpwnam(user);
  1894. X
  1895. X     if (psw) {
  1896. X      (void) strcpy(buf, psw->pw_dir);
  1897. X      return(0);
  1898. X     }
  1899. X     
  1900. X     psw = getpwuid((int) getuid());
  1901. X
  1902. X     if (psw) {
  1903. X      (void) strcpy(buf, psw->pw_dir);
  1904. X      return(0);
  1905. X     }
  1906. X
  1907. X     set_error(NO_HOME_DIR);
  1908. X     error("get_home");
  1909. X     return error_code;
  1910. X}
  1911. X
  1912. X
  1913. X
  1914. X
  1915. Xtimed_out(file_ent, current_time, min_days)
  1916. Xfilerec *file_ent;
  1917. Xtime_t current_time, min_days;
  1918. X{
  1919. X     if ((current_time - file_ent->specs.st_mtime) / 86400 >= min_days)
  1920. X      return(1);
  1921. X     else
  1922. X      return(0);
  1923. X}
  1924. X
  1925. X
  1926. X
  1927. Xint directory_exists(dirname)
  1928. Xchar *dirname;
  1929. X{
  1930. X     struct stat stat_buf;
  1931. X
  1932. X     if (stat(dirname, &stat_buf))
  1933. X      return(0);
  1934. X     else if ((stat_buf.st_mode & S_IFMT) == S_IFDIR)
  1935. X      return(1);
  1936. X     else
  1937. X      return(0);
  1938. X}
  1939. X
  1940. X
  1941. X
  1942. Xis_link(name, oldbuf)
  1943. Xchar *name;
  1944. Xstruct stat *oldbuf;
  1945. X{
  1946. X     struct stat statbuf;
  1947. X
  1948. X     if (oldbuf)
  1949. X      statbuf = *oldbuf;
  1950. X     else if (lstat(name, &statbuf) < 0) {
  1951. X      set_error(errno);
  1952. X      error("is_link");
  1953. X      return(0);
  1954. X     }
  1955. X
  1956. X     if ((statbuf.st_mode & S_IFMT) == S_IFLNK)
  1957. X      return 1;
  1958. X     else
  1959. X      return 0;
  1960. X}
  1961. X
  1962. X
  1963. X
  1964. X/*
  1965. X * This is one of the few procedures that is allowed to break the
  1966. X * rule of always returning an error value if an error occurs.  That's
  1967. X * because it's stupid to expect a boolean function to do that, and
  1968. X * because defaulting to not being a mountpoint if there is an error
  1969. X * is a reasonable thing to do.
  1970. X */
  1971. X/*
  1972. X * The second parameter is optional -- if it is non-NULL< it is
  1973. X * presumed to be a stat structure fo the file being passed in.
  1974. X */
  1975. Xint is_mountpoint(name, oldbuf)
  1976. Xchar *name;
  1977. Xstruct stat *oldbuf;
  1978. X{
  1979. X     struct stat statbuf;
  1980. X     dev_t device;
  1981. X     char buf[MAXPATHLEN];
  1982. X#ifdef AFS_MOUNTPOINTS
  1983. X     struct ViceIoctl blob;
  1984. X     char retbuf[MAXPATHLEN];
  1985. X     int retval;
  1986. X     char *shortname;
  1987. X#endif
  1988. X
  1989. X     /* First way to check for a mount point -- if the device number */
  1990. X     /* of name is different from the device number of name/..       */
  1991. X     if (oldbuf)
  1992. X      statbuf = *oldbuf;
  1993. X     else if (lstat(name, &statbuf) < 0) {
  1994. X      set_error(errno);
  1995. X      error(name);
  1996. X      return 0;
  1997. X     }
  1998. X
  1999. X     device = statbuf.st_dev;
  2000. X
  2001. X     if (strlen(name) + 4 /* length of "/.." + a NULL */ > MAXPATHLEN) {
  2002. X      set_error(ENAMETOOLONG);
  2003. X      error(name);
  2004. X      return 0;
  2005. X     }
  2006. X
  2007. X     strcpy(buf, name);
  2008. X     strcat(buf, "/..");
  2009. X     if (lstat(buf, &statbuf) < 0) {
  2010. X      set_error(errno);
  2011. X      error(name);
  2012. X      return 0;
  2013. X     }
  2014. X
  2015. X     if (statbuf.st_dev != device)
  2016. X      return 1;
  2017. X
  2018. X#ifdef AFS_MOUNTPOINTS
  2019. X     /* Check for AFS mountpoint using the AFS pioctl call. */
  2020. X     if ((shortname = lastpart(name)) == name) {
  2021. X      strcpy(buf, ".");
  2022. X      blob.in = name;
  2023. X      blob.in_size = strlen(name) + 1;
  2024. X      blob.out = retbuf;
  2025. X      blob.out_size = MAXPATHLEN;
  2026. X      bzero(retbuf, MAXPATHLEN);
  2027. X     }
  2028. X     else {
  2029. X      strncpy(buf, name, shortname - name - 1);
  2030. X      buf[shortname - name - 1] = '\0';
  2031. X      if (*buf == '\0')
  2032. X           strcpy(buf, "/");
  2033. X      blob.in = shortname;
  2034. X      blob.in_size = strlen(shortname) + 1;
  2035. X      blob.out = retbuf;
  2036. X      blob.out_size = MAXPATHLEN;
  2037. X      bzero(retbuf, MAXPATHLEN);
  2038. X     }
  2039. X
  2040. X     retval = pioctl(buf, VIOC_AFS_STAT_MT_PT, &blob, 0);
  2041. X
  2042. X     if (retval == 0) {
  2043. X#ifdef DEBUG
  2044. X      printf("%s is an AFS mountpoint, is_mountpoint returning true.\n",
  2045. X         name);
  2046. X#endif
  2047. X      return 1;
  2048. X     }
  2049. X     else {
  2050. X      if (errno != EINVAL) {
  2051. X           set_error(errno);
  2052. X           error(name);
  2053. X      }
  2054. X     }
  2055. X#endif /* AFS_MOUNTPOINTS */
  2056. X
  2057. X     return 0;
  2058. X}
  2059. X
  2060. X#ifdef MALLOC_DEBUG
  2061. Xchar *Malloc(size)
  2062. Xunsigned size;
  2063. X{
  2064. X     extern char *malloc();
  2065. X
  2066. X     static int count = 0;
  2067. X     char buf[10];
  2068. X     
  2069. X     count++;
  2070. X
  2071. X     fprintf(stderr, "This is call number %d to Malloc, for %u bytes.\n",
  2072. X         count, size);
  2073. X     fprintf(stdout, "Shall I return NULL for this malloc? ");
  2074. X     fgets(buf, 10, stdin);
  2075. X     if ((*buf == 'y') || (*buf == 'Y')) {
  2076. X      errno = ENOMEM;
  2077. X      return ((char *) NULL);
  2078. X     }
  2079. X     else
  2080. X      return (malloc(size));
  2081. X}
  2082. X#endif
  2083. X
  2084. X      
  2085. END_OF_FILE
  2086. if test 7849 -ne `wc -c <'util.c'`; then
  2087.     echo shar: \"'util.c'\" unpacked with wrong size!
  2088. fi
  2089. # end of 'util.c'
  2090. fi
  2091. echo shar: End of archive 2 \(of 3\).
  2092. cp /dev/null ark2isdone
  2093. MISSING=""
  2094. for I in 1 2 3 ; do
  2095.     if test ! -f ark${I}isdone ; then
  2096.     MISSING="${MISSING} ${I}"
  2097.     fi
  2098. done
  2099. if test "${MISSING}" = "" ; then
  2100.     echo You have unpacked all 3 archives.
  2101.     rm -f ark[1-9]isdone
  2102. else
  2103.     echo You still need to unpack the following archives:
  2104.     echo "        " ${MISSING}
  2105. fi
  2106. ##  End of shell archive.
  2107. exit 0
  2108. exit 0 # Just in case...
  2109.